import { init } from "snabbdom/build/package/init";
import { h } from "snabbdom/build/package/h";
import { eventListenersModule } from "snabbdom/build/package/modules/eventlisteners";
import { styleModule } from "snabbdom/build/package/modules/style";
import ORIGIN_DATA from "./data";

let totalHeight = 0;
const PADDING = 8;
const patch = init([styleModule, eventListenersModule]);

const app = document.getElementById("app");
const header = h("h1", "Top 10 movies");
const addBtn = h("a.btn.add", { on: { click: addMovie } }, "Add");
const btnGroup = h("span.btn-group", [
  h("a.btn.rank", { on: { click: sort("rank") } }, "Rank"),
  h("a.btn.title", { on: { click: sort("title") } }, "Title"),
  h("a.btn.desc", { on: { click: sort("desc") } }, "Description"),
]);
const topBar = [header, h("div", ["Sort by: ", btnGroup, addBtn])];

let movieData = [...ORIGIN_DATA];
const movieItem = (item) => [
  h("div", item.rank),
  h("div", item.title),
  h("div", item.desc),
  h("div.rm-btn", { on: { click: removeMovie(item.rank) } }, "X"),
];
const movies = () =>
  h(
    "div.list",
    { style: { height: totalHeight + "px" } },
    movieData.map((item) => {
      return h(
        "div.row",
        {
          key: item.rank,
          style: {
            opacity: "0",
            transform: "translate(-200px)",
            delayed: { transform: "translateY(" + item.offset + "px)", opacity: "1" },
            remove: { opacity: "0", transform: "translateY(" + item.offset + "px) translateX(200px)" },
          },
          hook: {
            insert(vnode) {
              item.elmHeight = vnode.elm.offsetHeight;
            },
          },
        },
        movieItem(item)
      );
    })
  );

const newVNode = () => h("div#app", [...topBar, movies()]);
let oldVNode = patch(app, newVNode());
render();

// 版本2之后必须用闭包的方式才能访问到传入的参数（ugly way）
function sort(sortBy) {
  return () => {
    movieData.sort((a, b) => {
      if (a[sortBy] > b[sortBy]) return 1;
      if (a[sortBy] < b[sortBy]) return -1;
      return 0;
    });
    render();
  };
}

function addMovie() {
  const item = ORIGIN_DATA[Math.floor(Math.random() * 10)];
  movieData.unshift({ ...item, rank: movieData.length + 1, elmHeight: 0 });
  render();
}

function removeMovie(rank) {
  return () => {
    movieData = movieData.filter((item) => item.rank !== rank);
    render();
  };
}

function updateOffset() {
  movieData = movieData.reduce((acc, cur) => {
    const last = acc[acc.length - 1];
    cur.offset = last ? last.offset + last.elmHeight + PADDING : PADDING;
    return acc.concat(cur);
  }, []);
}

function updateView() {
  oldVNode = patch(oldVNode, newVNode());
}

function render() {
  updateView();
  updateOffset();
  updateView();
}
